package com.framework.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.framework.dao.AgentInfoDao;
import com.framework.entity.aliPay.AliPayConfig;
import com.framework.entity.flow.FlowAccount;
import com.framework.entity.flow.FlowTask;
import com.framework.entity.sys.*;
import com.framework.entity.tran.AliPayerAgent;
import com.framework.exception.NoRollBackException;
import com.framework.exception.RRException;
import com.framework.exception.menu.RespCode;
import com.framework.page.PageUtils;
import com.framework.page.Query;
import com.framework.service.*;
import com.framework.utils.AesUtil;
import com.framework.utils.MD5Util;
import com.framework.utils.ali.AliPay;
import com.framework.utils.pay.lianpay.LianLianPay;
import com.framework.utils.pay.suixingfu.SuiXingFuPay;
import com.framework.utils.pay.youfupay.method.AccountQueryMethod;
import com.framework.utils.pay.youfupay.method.PayMethod;
import com.framework.utils.pay.youfupay.method.SignContractQueryMethod;
import com.framework.utils.pay.yunzhanghujiesuan.YunJieSuanPay;
import com.framework.utils.string.StringUtil;
import com.framework.validator.Assert;
import com.google.gson.Gson;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sun.misc.REException;

import java.math.BigDecimal;
import java.util.Map;

/**
 * 代理商信息
 *
 * @author wq
 */
@Service("agentInfoService")
public class AgentInfoServiceImpl extends ServiceImpl<AgentInfoDao, SysAgentInfo> implements AgentInfoService {

    @Autowired
    private AgentService agentService;
    @Autowired
    private AgentInfoService agentInfoService;

    @Autowired
    private PaymentService paymentService;
    @Autowired
    private BankService bankService;
    @Autowired
    private FlowTaskService flowTaskService;
    @Autowired
    private FlowAccountService flowAccountService;
    @Autowired
    private AliPayerAgentService aliPayerAgentService;
    @Autowired
    private TranOrderService tranOrderService;
    @Autowired
    private DeptSmsService deptSmsService;

    @Autowired
    private DictService dictService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        Page<SysAgentInfo> page = this.selectPage(
                new Query<SysAgentInfo>(params).getPage(),
                new EntityWrapper<>()
        );
        return new PageUtils(page);
    }

    @Override
    public SysAgentInfo getAgentInfoById(Long agentId) {
        SysAgentInfo a = new SysAgentInfo();
        a.setAgentId(agentId);
        SysAgentInfo agent = baseMapper.selectOne(a);
        return agent;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void insertAgentInfo(Long agentId) {
        if (agentId == null || agentId == 0) {
            throw new RRException(RespCode.NOT_PARAM_ERROR);
        }
        //查询是否存在
        SysAgent sysAgent = agentService.queryAgentById(agentId);
        Assert.isNull(sysAgent, "未查询到代理商基础信息");
        SysAgentInfo sysAgentInfo = new SysAgentInfo();
        sysAgentInfo.setAgentId(agentId);
        baseMapper.insert(sysAgentInfo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void reduceBalance(Long agentId, BigDecimal amount) {
        baseMapper.reduceBalance(agentId, amount);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateTaskPassword(String password, String confPassword, String token, String vCode) {
        if (StringUtils.isBlank(password) ||
                StringUtils.isBlank(confPassword) ||
                StringUtils.isBlank(token) ||
                StringUtils.isBlank(vCode)) {
            throw new RRException(RespCode.NOT_PARAM_ERROR);
        }
        SysAgent agent = agentService.queryAgentByToken(token);
        String phone = agent.getPhone();
        Long agentId = agent.getAgentId();
        SysAgentInfo info = getAgentInfoById(agentId);
        if (info == null) {
            throw new RRException("9000", "未查询到代理商详细信息");
        }
        if (!StringUtils.equals(password, confPassword)) {
            throw new RRException("9000", "二次密码不一致");
        }
        //判断验证码
        deptSmsService.checkSms("t_forget", phone, vCode);
        //AES解密
        String textPassword = AesUtil.aesDecrypt(password);
        Assert.isBlank(textPassword, "加密错误");
        //MD5加盐加密
        String MD5Password = MD5Util.string2MD5(textPassword);

        info.setTakePassword(MD5Password);
        baseMapper.updateAgentInfoById(info);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void takeMoney(String token, String password, BigDecimal money, String bankNo) {
        throw new RRException("9000", "提现渠道错误,请更新app");
       /* SysAgent agent = agentService.queryAgentByToken(token);

        Long agentId = agent.getAgentId();
        //查看数据库中代理商的信息
        SysAgent sysAgent = agentService.queryAgentById(agentId);
        if (sysAgent.getState() == 2) {
            throw new RRException("9000", "账户已经被封禁");
        }
        if (sysAgent.getState().intValue() == 3) {
            if (sysAgent.getDeptId().equals(889323L)) {
                throw new RRException("9000", "提现休眠状态，请联系客服");
            } else {

                throw new RRException("9000", "提现暂被封禁,请联系客服");
            }
        }
        if (StringUtils.equals(sysAgent.getRealName(), "未认证") || "0".equals(sysAgent.getRealName())) {
            throw new RRException("9000", "账户还未实名认证");
        }
        SysAgentInfo agentInfo = getAgentInfoById(agentId);
        if (agentInfo == null) {
            throw new RRException("9000", "未查询到代理商的详细信息");
        }


        if (!StringUtils.equals(password, agentInfo.getTakePassword())) {
            throw new RRException("9000", "提现密码错误");
        }
        //可提分润
        BigDecimal AvailableAmount = agentInfo.getAvailableAmount();
        if (AvailableAmount.compareTo(money) == -1) {
            throw new RRException("9000", "可提余额不足");
        }


        //查询代付配置信息
        SysPayment payment = paymentService.queryPaymentByDeptId(agent.getDeptId());
        if (payment == null) {
            throw new RRException("9000", "未查询到代付配置信息");
        }
        if (payment.getState().intValue() == 2) {
            throw new RRException("9000", payment.getRemark());
        }
        //每笔扣除税率和单笔钱
        BigDecimal chargeAmount = payment.getChargeAmount();
        BigDecimal chargeRate = payment.getChargeRate();
        if (money.compareTo(chargeAmount) == -1) {
            throw new RRException("9000", "每笔提现金额必须大于" + chargeAmount + "元");
        }

        //扣除税率 先扣除税率/再减去每笔的钱
        BigDecimal rateMoney = money.multiply(chargeRate.divide(new BigDecimal("100")));
        //总共手续费
        BigDecimal allRateMoney = rateMoney.add(chargeAmount);
        //实际提现的金额
        BigDecimal actualMoney = money.subtract(allRateMoney);
        actualMoney = actualMoney.setScale(2, BigDecimal.ROUND_HALF_UP);
        //生成订单号
        String orderNo = StringUtil.getDateString(6);

        //所属类型 1：连连 2：随行付 3:支付宝 4:云账户
        Integer payType = payment.getPayType();
        String clientId = payment.getClientId();
        String privateKey = payment.getPrivateKey();
        String publicKey = payment.getPublicKey();
        FlowTask task = new FlowTask();
        //存入实时可提现金额
        task.setCurrentAmount(agentInfo.getAvailableAmount());
        SysBank bank;
        //连连支付
        if (payType.intValue() == 1) {
            //银行卡信息查询
            bank = getSysBank(bankNo, agent, agentId);
            try {
                //LianLianPay.payment(orderNo, dateTime, String.valueOf(actualMoney), bank.getBankNo(), bank.getCardName(), "余额提现", "0", "https://www.syzmpos.com/mpos-api/v1/notValidate/lianlianPayCallback", "余额提现", publicKey, privateKey, clientId);
                task.setExplains("提现审核中");
                task.setTakeType(1);
            } catch (Exception e) {
                throw new RRException("9000", e.getMessage());
            }
            //2：随行付
        } else if (payType.intValue() == 2) {
            //银行卡信息查询
            bank = getSysBank(bankNo, agent, agentId);
            //随行付
            String lineNo = bank.getLineNo();
            if (StringUtils.isBlank(lineNo)) {
                throw new RRException("9000", "银行行号为空");
            }
            SuiXingFuPay.suiXingFuPay(String.valueOf(actualMoney), orderNo, bank.getCardName(), bank.getBankNo(), bank.getBankCode(), bank.getBankName(), agent.getPhone(), lineNo, publicKey, privateKey, clientId);
            task.setTaskState("EXAMINE");
            task.setExplains("提现审核中");
            task.setTakeType(2);
            //支付宝
        } else if (payType.intValue() == 3) {
            AliPayerAgent aliPayerAgent = aliPayerAgentService.queryAliAccount(token);
            if (aliPayerAgent == null) {
                throw new RRException("9000", "请绑定支付宝账号");
            }
            AliPayConfig aliPayConfig = ordersService.queryAliPayConfig(agent.getDeptId());
            String remark = "";
            if (agent.getDeptId().equals(889323L)) {
                remark = "卡一平台提现";
            }
            AliPay.aLiTransfer(aliPayConfig, orderNo, aliPayerAgent.getAliAccount(), aliPayerAgent.getName(), actualMoney, remark);
            task.setTaskState("EXAMINE");
            task.setExplains("提现审核中");
            task.setTakeType(3);
            //云账户支付
        } else if (payType.intValue() == 4) {
            //银行卡信息查询
            bank = getSysBank(bankNo, agent, agentId);

            //提现之前查询余额，防止余额不足
            Boolean flag = YunJieSuanPay.queryAccountAmount(String.valueOf(actualMoney), payment);

            if (flag) {
                throw new RRException("9000", "当前提现人数过多，请稍后再试");
            }

            //提现方法
            YunJieSuanPay.yunJieSuanPay(orderNo, bank, agentInfo.getIdCard(), String.valueOf(actualMoney), payment, payment.getPayName());

            task.setTaskState("EXAMINE");
            task.setExplains("提现审核中");
            task.setTakeType(4);
        }

        //扣除可用余额
        agentInfoService.reduceBalance(agentId, money);
        BigDecimal afterAmount = agentInfo.getAvailableAmount().subtract(money);
        //存入提现后金额
        task.setAfterAmount(afterAmount);
        //添加提现流水
        task.setServiceAmount(allRateMoney);
        task.setTakeNo(orderNo);
        task.setActAccountAmount(actualMoney);
        task.setAgentId(agentId);
        task.setTakeAmount(money);
        flowTaskService.insertFlowTask(task);
        //添加账户日志
        FlowAccount flowAccount = new FlowAccount();
        flowAccount.setSupportType(1);
        flowAccount.setBelId(orderNo);
        flowAccount.setAmount(money);
        flowAccount.setAgentId(agentId);
        flowAccount.setAccountType(1);
        flowAccountService.insertFlowAccount(flowAccount);

        */
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addBalance(Long agentId, BigDecimal amount) {
        baseMapper.addBalance(agentId, amount);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateAgentInfoById(SysAgentInfo agentInfo) {
        baseMapper.updateAgentInfoById(agentInfo);
    }

    @Override
    public void addAmount(Long agentId, BigDecimal amount) {
        baseMapper.addAmount(agentId, amount);
    }

    @Override
    public Map<String, Object> queryTakeSum(Long deptId) {
        return baseMapper.queryTakeSum(deptId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void reduceFreeznAmount(Long agentId, BigDecimal takeAmount) {
        baseMapper.reduceFreeznAmount(agentId, takeAmount);
    }

    @Override
    public void reduceAmount(Long agentId, BigDecimal trueAmount) {
        SysAgentInfo i = new SysAgentInfo();
        i.setAgentId(agentId);
        SysAgentInfo info = baseMapper.selectOne(i);
        info.setTotalAmount(info.getTotalAmount().subtract(trueAmount));
        info.setAvailableAmount(info.getAvailableAmount().subtract(trueAmount));
        baseMapper.updateById(info);
    }

    @Transactional(rollbackFor = Exception.class,noRollbackFor = NoRollBackException.class)
    @Override
    public void takeAmount(String token, String password, BigDecimal money, String bankNo) {
        Assert.isNull(money, "提现金额不能为空");
        SysAgent agent = agentService.queryAgentByToken(token);

        Long agentId = agent.getAgentId();
        //查看数据库中代理商的信息
        SysAgent sysAgent = agentService.queryAgentById(agentId);
        if (sysAgent.getState() == 2) {
            throw new RRException("9000", "账户已经被封禁");
        }
        if (sysAgent.getState().intValue() == 3) {
            if (sysAgent.getDeptId().equals(889323L)) {
                throw new RRException("9000", "提现休眠状态，请联系客服");
            } else {

                throw new RRException("9000", "提现暂被封禁,请联系客服");
            }
        }
        if ("0".equals(sysAgent.getRealName())) {
            throw new RRException("9000", "账户还未实名认证");
        }
        SysAgentInfo agentInfo = getAgentInfoById(agentId);
        if (agentInfo == null) {
            throw new RRException("9000", "未查询到代理商的详细信息");
        }

        String result = AesUtil.aesDecrypt(password);

        Assert.isBlank(result, "解密错误");
        String pwd = MD5Util.string2MD5(result);
        if (!StringUtils.equals(pwd, agentInfo.getTakePassword())) {
            throw new RRException("9000", "提现密码错误");
        }
        //可提分润
        BigDecimal AvailableAmount = agentInfo.getAvailableAmount();
        if (AvailableAmount.compareTo(money) == -1) {
            throw new RRException("9000", "可提余额不足");
        }


        //查询代付配置信息
        SysPayment payment = paymentService.queryPaymentByDeptId(agent.getDeptId());
        if (payment == null) {
            throw new RRException("9000", "未查询到代付配置信息");
        }
        if (payment.getState().intValue() == 2) {
            throw new RRException("9000", payment.getRemark());
        }
        BigDecimal minAmount = payment.getMinAmount();

        if (money.compareTo(minAmount) == -1) {
            throw new RRException("9000", "提现金额必须大于" + minAmount + "元");
        }

        //每笔扣除税率和单笔钱
        BigDecimal chargeAmount = payment.getChargeAmount();
        BigDecimal chargeRate = payment.getChargeRate();
        if (money.compareTo(chargeAmount) == -1) {
            throw new RRException("9000", "每笔提现金额必须大于" + chargeAmount + "元");
        }

        //扣除税率 先扣除税率/再减去每笔的钱
        BigDecimal rateMoney = money.multiply(chargeRate.divide(new BigDecimal("100")));
        //总共手续费
        BigDecimal allRateMoney = rateMoney.add(chargeAmount);
        //实际提现的金额
        BigDecimal actualMoney = money.subtract(allRateMoney).setScale(2,BigDecimal.ROUND_HALF_UP);

        //生成订单号
        String orderNo = StringUtil.getDateString(6);
        //所属类型 1：连连 2：随行付 3:支付宝
        Integer payType = payment.getPayType();

        FlowTask task = new FlowTask();
        //存入实时可提现金额
        task.setCurrentAmount(agentInfo.getAvailableAmount());
        //连连支付
       /* if (payType.intValue() == 1) {
            //银行卡信息查询
            bank = bankService.selectBankByNo(bankNo, agent.getDeptId());
            if (bank == null) {
                throw new RRException("9000", "未查询到银行卡信息");
            }
            if (!agentId.equals(bank.getAgentId())) {
                throw new RRException("9000", "提现银行卡不属于您");
            }
            try {
               // LianLianPay.payment(orderNo, dateTime, String.valueOf(actualMoney), bank.getBankNo(), bank.getCardName(), "余额提现", "0", "https://www.syzmpos.com/mpos-api/v1/notValidate/lianlianPayCallback", "余额提现", publicKey, privateKey, clientId);
                task.setExplains("提现审核中");
                task.setTakeType(1);
            } catch (Exception e) {
                throw new RRException("9000", e.getMessage());
            }
        } else if (payType.intValue() == 2) {//2：随行付
            //银行卡信息查询
            bank = bankService.selectBankByNo(bankNo, agent.getDeptId());
            if (bank == null) {
                throw new RRException("9000", "未查询到银行卡信息");
            }
            if (!agentId.equals(bank.getAgentId())) {
                throw new RRException("9000", "提现银行卡不属于您");
            }
            //随行付
            String lineNo = bank.getLineNo();
            if (StringUtils.isBlank(lineNo)) {
                throw new RRException("9000", "银行行号为空");
            }
            SuiXingFuPay.suiXingFuPay(String.valueOf(actualMoney), orderNo, bank.getCardName(), bank.getBankNo(), bank.getBankCode(), bank.getBankName(), agent.getPhone(), lineNo, publicKey, privateKey, clientId);
            task.setTaskState("EXAMINE");
            task.setExplains("提现审核中");
            task.setTakeType(2);
        } else */
        //支付宝
        if (payType.intValue() == 3) {
            AliPayerAgent aliPayerAgent = aliPayerAgentService.queryAliAccount(token);
            if (aliPayerAgent == null) {
                throw new RRException("9000", "请绑定支付宝账号");
            }
            AliPayConfig aliPayConfig = tranOrderService.queryAliPayConfig(agent.getDeptId());
            String remark = "卡一平台提现";

            AliPay.aLiTransfer(aliPayConfig, orderNo, aliPayerAgent.getAliAccount(), aliPayerAgent.getName(), actualMoney, remark);
            task.setTaskState("EXAMINE");
            task.setExplains("提现审核中");
            task.setTakeType(3);
            //云账户支付
        } else if (payType.intValue() == 4) {

            SysBank bank = getSysBank(bankNo, agent, agentId);

            if(agent.getDeptId().equals(1L)){
                task.setTaskState("SUCCESS");
                task.setExplains("提现成功");
                task.setTakeType(4);
            }else {
                //提现之前查询余额，防止余额不足
                if (YunJieSuanPay.queryAccountAmount(String.valueOf(actualMoney), payment)) {
                    throw new RRException("9000", "当前提现人数过多，请稍后再试");
                }

                //提现方法
                YunJieSuanPay.yunJieSuanPay(orderNo, bank, agentInfo.getIdCard(), String.valueOf(actualMoney), payment, payment.getPayName());

                task.setTaskState("EXAMINE");
                task.setExplains("提现审核中");
                task.setTakeType(4);
                task.setHasCommit(1);
            }




        } else if (payType.intValue() == 5) {

            SysBank bank = getSysBank(bankNo, agent, agentId);
            SysDict secretKey = dictService.querySysDict(agent.getDeptId().intValue(), "1", "pay_secret_key");
            SysDict levyId = dictService.querySysDict(agent.getDeptId().intValue(), "1", "pay_lay_id");

            if(bank.getIsReserved().intValue()==0){
                throw new RRException("0024","您尚未完善提现信息，请完善信息");
            }

            if(bank.getIsReserved().intValue()==2){
                Integer state = SignContractQueryMethod.signContractQuery(payment, secretKey.getValue(), bank, levyId.getValue(), agentInfo.getIdCard());
                if(state.intValue()==0){
                    throw new RRException("9000","第三方代付签约中,请稍后再试");
                }else if(state.intValue()==2){
                    bank.setIsReserved(0);
                    bankService.updateById(bank);
                    throw new NoRollBackException("0024","未查询到您的签约信息,请签约");
                }
            }

            BigDecimal total = AccountQueryMethod.accountQuery(secretKey.getValue(), payment, levyId.getValue());

            System.out.println(total.toString());
            if (actualMoney.compareTo(total) == 1) {
                throw new RRException("9000", "当前提现人数过多，请稍后再试");
            }
            String batchId="batch"+System.currentTimeMillis();
            String takeMoney=actualMoney.multiply(new BigDecimal(100)).toString();
            takeMoney=takeMoney.substring(0,takeMoney.indexOf("."));
            PayMethod.pay(payment, bank, agentInfo.getIdCard(), secretKey.getValue(), takeMoney, orderNo, batchId,levyId.getValue());
            task.setTaskState("EXAMINE");
            task.setExplains("提现审核中");
            task.setTakeType(5);
            task.setBatchId(batchId);
            if(bank.getIsReserved().intValue()==2){
                bank.setIsReserved(1);
                bankService.updateById(bank);
            }
        } else {
            throw new RRException("9000", "提现方式错误");
        }
        //扣除可用余额
        agentInfoService.reduceBalance(agentId, money);
        BigDecimal afterAmount = agentInfo.getAvailableAmount().subtract(money);
        //存入提现后金额
        task.setAfterAmount(afterAmount);
        //添加提现流水
        task.setServiceAmount(allRateMoney);
        task.setTakeNo(orderNo);
        task.setActAccountAmount(actualMoney);
        task.setAgentId(agentId);
        task.setTakeAmount(money);
        task.setDeptId(agent.getDeptId());
        flowTaskService.insertFlowTask(task);
        //添加账户日志
        FlowAccount flowAccount = new FlowAccount();
        flowAccount.setSupportType(1);
        flowAccount.setBelId(orderNo);
        flowAccount.setAmount(money);
        flowAccount.setAgentId(agentId);
        flowAccount.setAccountType(1);
        flowAccountService.insertFlowAccount(flowAccount);
    }

    private SysBank getSysBank(String bankNo, SysAgent agent, Long agentId) {
        SysBank bank = bankService.selectBankByNo(bankNo, agent.getDeptId());

        if (bank == null) {
            throw new RRException("9000", "未查询到银行卡信息");
        }
        if (!agentId.equals(bank.getAgentId())) {
            throw new RRException("9000", "提现银行卡不属于您");
        }
        return bank;
    }

    @Override
    public void addFrozen(Long agentId, BigDecimal reapAmount) {
        SysAgentInfo info = getAgentInfoById(agentId);
        BigDecimal frozenAmount = info.getFreeznAmount();
        BigDecimal decimal = frozenAmount.add(reapAmount);
        info.setFreeznAmount(decimal);
        baseMapper.updateById(info);

    }

    @Override
    public void thawAmount(Long agentId, BigDecimal amount) {
        SysAgentInfo info = getAgentInfoById(agentId);
        BigDecimal frozenAmount = info.getFreeznAmount();
        BigDecimal availableAmount = info.getAvailableAmount();
        BigDecimal totalAmount = info.getTotalAmount();

        info.setAvailableAmount(availableAmount.add(amount));

        info.setTotalAmount(totalAmount.add(amount));

        BigDecimal decimal = frozenAmount.subtract(amount);
        info.setFreeznAmount(decimal);
        baseMapper.updateById(info);
    }


}
